| 1 | pub fn syscall1(number: usize, arg1: usize) usize { |
| 2 | // Inline assembly is an expression which returns a value. |
| 3 | // the `asm` keyword begins the expression. |
| 4 | return asm |
| 5 | // `volatile` is an optional modifier that tells Zig this |
| 6 | // inline assembly expression has side-effects. Without |
| 7 | // `volatile`, Zig is allowed to delete the inline assembly |
| 8 | // code if the result is unused. |
| 9 | volatile ( |
| 10 | // Next is a comptime string which is the assembly code. |
| 11 | // Inside this string one may use `%[ret]`, `%[number]`, |
| 12 | // or `%[arg1]` where a register is expected, to specify |
| 13 | // the register that Zig uses for the argument or return value, |
| 14 | // if the register constraint strings are used. However in |
| 15 | // the below code, this is not used. A literal `%` can be |
| 16 | // obtained by escaping it with a double percent: `%%`. |
| 17 | // Often multiline string syntax comes in handy here. |
| 18 | \\syscall |
| 19 | // Next is the output. It is possible in the future Zig will |
| 20 | // support multiple outputs, depending on how |
| 21 | // https://github.com/ziglang/zig/issues/215 is resolved. |
| 22 | // It is allowed for there to be no outputs, in which case |
| 23 | // this colon would be directly followed by the colon for the inputs. |
| 24 | : |
| 25 | // This specifies the name to be used in `%[ret]` syntax in |
| 26 | // the above assembly string. This example does not use it, |
| 27 | // but the syntax is mandatory. |
| 28 | [ret] |
| 29 | // Next is the output constraint string. This feature is still |
| 30 | // considered unstable in Zig, and so LLVM/GCC documentation |
| 31 | // must be used to understand the semantics. |
| 32 | // http://releases.llvm.org/10.0.0/docs/LangRef.html#inline-asm-constraint-string |
| 33 | // https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html |
| 34 | // In this example, the constraint string means "the result value of |
| 35 | // this inline assembly instruction is whatever is in $rax". |
| 36 | "={rax}" |
| 37 | // Next is either a value binding, or `->` and then a type. The |
| 38 | // type is the result type of the inline assembly expression. |
| 39 | // If it is a value binding, then `%[ret]` syntax would be used |
| 40 | // to refer to the register bound to the value. |
| 41 | (-> usize), |
| 42 | // Next is the list of inputs. |
| 43 | // The constraint for these inputs means, "when the assembly code is |
| 44 | // executed, $rax shall have the value of `number` and $rdi shall have |
| 45 | // the value of `arg1`". Any number of input parameters is allowed, |
| 46 | // including none. |
| 47 | : [number] "{rax}" (number), |
| 48 | [arg1] "{rdi}" (arg1), |
| 49 | // Next is the list of clobbers. These declare a set of registers whose |
| 50 | // values will not be preserved by the execution of this assembly code. |
| 51 | // These do not include output or input registers. The special clobber |
| 52 | // value of "memory" means that the assembly writes to arbitrary undeclared |
| 53 | // memory locations - not only the memory pointed to by a declared indirect |
| 54 | // output. In this example we list $rcx and $r11 because it is known the |
| 55 | // kernel syscall does not preserve these registers. |
| 56 | : .{ .rcx = true, .r11 = true }); |
| 57 | } |
| 58 | |
| 59 | // syntax |